package com.e2j.utils.json;

import com.alibaba.fastjson2.JSONArray;
import com.e2j.lib.ILibItem;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 读取Json文件成为数组或字典。
 * 依赖FastJson
 *
 * @param <K> Map的键值
 * @param <V> 类
 * @author Seraph.Yang
 *
 * <dependency>
 * <groupId>com.alibaba</groupId>
 * <artifactId>fastjson</artifactId>
 * <version>1.2.73</version>
 * </dependency>
 */
public class JsonHashMapReader<K, V> {

    private IJsonData jsonData;

    /**
     * 读取json文件成为Hashmap
     * 使用：先创建类读取文件，然后用getMap
     *
     * @throws IOException
     */
    public JsonHashMapReader(IJsonData jsonData) {
        this.jsonData = jsonData;
    }

    /**
     * 预读vo初始化处理
     * @param mapObj
     */
    public void preloadVo(Object mapObj) {
        if (mapObj instanceof ILibItem) {
            ILibItem item = (ILibItem) mapObj;
            item.preload();;
        }
    }

    /**
     * 把json数组反序列化为HashMap
     *
     * @param clazz        Map的value值对应的类
     * @param keyFieldName 反射Map的Key字段名（字符）
     * @return 读取后的Map
     * @throws NoSuchFieldException
     */
    public Map<K, V> getMap(Class clazz, String keyFieldName) throws NoSuchFieldException {
        return getMap(clazz, keyFieldName, null);
    }

    /**
     * 把json数组反序列化为HashMap
     *
     * @param clazz        Map的value值对应的类
     * @param keyFieldName 反射Map的Key字段名（字符）
     * @param readTagName  指定节点； 如果不填，则认定root就是一个数组
     * @return 读取后的Map
     * @throws NoSuchFieldException
     */
    public Map<K, V> getMap(Class clazz, String keyFieldName, String readTagName) throws NoSuchFieldException {
        jsonData.readJsonArray(readTagName);
        Map<K, V> map = new HashMap<>();
        JSONArray jsonArr = jsonData.getJsonArr();
        if (jsonArr == null) {
            return map;
        }
        for (int i = 0; i < jsonArr.size(); i++) {
            Object mapObj = jsonArr.getObject(i, clazz);
            this.preloadVo(mapObj);//预处理
            Field[] fs = clazz.getDeclaredFields();
            for (int j = 0; j < fs.length; j++) {
                Field f = fs[j];
                f.setAccessible(true); // 设置些属性是可以访问的
                Object keyValue = new Object();
                try {
                    if (keyFieldName == f.getName()) {
                        keyValue = f.get(mapObj);
                        map.put((K) keyValue, (V) mapObj);
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    /**
     * 把json数组反序列化为HashMap
     * (Integer专用，因为Integer用getMap，Key会识别为String)
     *
     * @param clazz        Map的value值对应的类
     * @param keyFieldName 反射Map的Key字段名（字符）
     * @param readTagName  指定节点； 如果不填，则认定root就是一个数组
     * @return 读取后的Map
     * @throws NoSuchFieldException
     */
    public Map<Integer, V> getIntegerKeyMap(Class clazz, String keyFieldName, String readTagName) throws NoSuchFieldException {
        jsonData.readJsonArray(readTagName);
        Map<Integer, V> map = new HashMap<>();
        JSONArray jsonArr = jsonData.getJsonArr();
        if (jsonArr == null) {
            return map;
        }
        for (int i = 0; i < jsonArr.size(); i++) {
            Object mapObj = jsonArr.getObject(i, clazz);
            this.preloadVo(mapObj);//预处理
            Field[] fs = clazz.getDeclaredFields();
            for (int j = 0; j < fs.length; j++) {
                Field f = fs[j];
                // 设置些属性是可以访问的
                f.setAccessible(true);
                try {
                    if (keyFieldName.equals(f.getName())) {
                        Object objKey = f.get(mapObj);
                        Integer key;
                        if (objKey instanceof Integer) {
                            key = (Integer) objKey;
                        } else if (objKey instanceof String) {
                            key = Integer.parseInt((String) objKey);
                        } else {
                            throw new Error("不合法的json类型");
                        }
                        map.put(key, (V) mapObj);
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }


    /**
     * 把json数组反序列化为HashMap
     * (String专用)
     *
     * @param clazz        Map的value值对应的类
     * @param keyFieldName 反射Map的Key字段名（字符）
     * @param readTagName  指定节点； 如果不填，则认定root就是一个数组
     * @return 读取后的Map
     * @throws NoSuchFieldException
     */
    public Map<String, V> getStringKeyMap(Class clazz, String keyFieldName, String readTagName) throws NoSuchFieldException {
        jsonData.readJsonArray(readTagName);
        Map<String, V> map = new HashMap<>();
        JSONArray jsonArr = jsonData.getJsonArr();
        if (jsonArr == null) {
            return map;
        }
        for (int i = 0; i < jsonArr.size(); i++) {
            Object mapObj = jsonArr.getObject(i, clazz);
            this.preloadVo(mapObj);//预处理
            Field[] fs = clazz.getDeclaredFields();
            for (int j = 0; j < fs.length; j++) {
                Field f = fs[j];
                f.setAccessible(true); // 设置些属性是可以访问的
                Object keyValue = new Object();
                try {
                    if (keyFieldName.equals(f.getName())) {
                        Object objKey = f.get(mapObj);
                        String key;
                        if (objKey instanceof String) {
                            key = (String) objKey;
                        } else {
                            throw new Error("不合法的json类型");
                        }
                        map.put(key, (V) mapObj);
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    public Map<String, V> getMultKeyMap(Class clazz, String[] keyFieldNames, String readTagName) throws NoSuchFieldException {
        jsonData.readJsonArray(readTagName);
        Map<String, V> map = new HashMap<>();
        JSONArray jsonArr = jsonData.getJsonArr();
        if (jsonArr == null) {
            return map;
        }
        for (int i = 0; i < jsonArr.size(); i++) {
            Object mapObj = jsonArr.getObject(i, clazz);
            this.preloadVo(mapObj);//预处理
            Field[] fs = clazz.getDeclaredFields();
            String key = "";
            for (int j = 0; j < fs.length; j++) {
                Field f = fs[j];
                f.setAccessible(true); // 设置些属性是可以访问的
                Object keyValue = new Object();
                try {
                    for (int kfOrd = 0; kfOrd < keyFieldNames.length; kfOrd++) {
                        String keyFieldName = keyFieldNames[kfOrd];
                        if (keyFieldName.equals(f.getName())) {
                            Object objKey = f.get(mapObj);
                            if (objKey instanceof String) {
                                key += (String) objKey + "_";
                            } else if (objKey instanceof Integer) {
                                key += ((Integer) objKey).toString() + "_";
                            } else if (objKey instanceof Boolean) {
                                key += ((Boolean) objKey).toString() + "_";
                            } else {
                                throw new Error("不合法的json类型");
                            }
                        }
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            if (!key.equals("")) {
                map.put(key, (V) mapObj);
            } else {
                throw new Error("加载MultKeyMap错误，键值为空!");
            }
        }
        return map;
    }

}
